<?php

require_once "db_lib.php";

define("MAX_LATITUDE", 90.0);
define("MAX_LONGITUDE", 180.0);
define("MAX_ALTITUDE", 29030); // height of Mt. Everest
define("MIN_ALTITUDE", -1237); // elevation of the Dead Sea

class ID {
	private $id;
	
	public function __construct($i) {
		if (!is_numeric($i) || ((int)$i) < 0) {
			throw new Exception("InvalidID: ".$i);
			
		}
		$this->id = ((int)$i);
	}
	
	public function value() {
		return $this->id;
	}
}

class Timestamp {
	private $timestamp;
	private $month;
	private $day;
	private $year;
	
	public function __construct($t) {
		$stamp = strtotime($t, 0);
		if ($stamp === false || !is_numeric($stamp)) {
			throw new Exception("InvalidTimestamp: ".$t);
		}
		
		$month = date('m', $stamp);
  		$day   = date('d', $stamp);
  		$year  = date('Y', $stamp);
 
  		if (!checkdate($month, $day, $year)) {
     		throw new Exception("InvalidTimestamp: ".$t);
  		} 
 
 		$this->timestamp = $t;
 		$this->month = $month;
 		$this->day = $day;
 		$this->year = $year;
	}
	
	public function month() {
		return $this->month;
	}
	
	public function day() {
		return $this->day;
	}
	
	public function year() {
		return $this->year;
	}
	
	public function value() {
		return $this->timestamp;
	}
}

class Latitude {
	private $latitude;
	
	public function __construct($l) {
		if (!is_numeric($l) || ((float)$l) < -(MAX_LATITUDE) || ((float)$l) > MAX_LATITUDE) {
			throw new Exception("InvalidLatitudeException: ".$l);
		}
		
		$this->latitude = ((float)$l);
	}
	
	public function value() {
		return $this->latitude;
	}
}

class Longitude {
	private $longitude;
	
	public function __construct($l) {
		if (!is_numeric($l) || ((float)$l) < -(MAX_LONGITUDE) || ((float)$l) > MAX_LONGITUDE) {
			throw new Exception("InvalidLongitudeException: ".$l);
		}
		
		$this->longitude = ((float)$l);
	}
	
	public function value() {
		return $this->longitude;
	}
}

class Altitude {
	private $altitude;
	
	public function __construct($a) {
		if (!is_numeric($a) || ((float)$a) < MIN_ALTITUDE || ((float)$a) > MAX_ALTITUDE) {
			throw new Exception("InvalidAltitudeException: ".$a);
		}
		
		$this->altitude = ((float)$a);
	}
	
	public function value() {
		return $this->altitude;
	}
}

class URL {
	private $url;
	
	public function __construct($u) {
		if (!is_string($u)) {
			// TODO: validate URL?
			throw new Exception("InvalidURLException: ".$u);
		}
		$this->url = $u;
	}
	
	public function value() {
		return $this->url;
	}
}

class Orientation {
	private $orientation;
	
	public function __construct($o) {
		if (!is_numeric($o) ||
			(((int)$o) != 0 && ((int)$o) != 90 &&
			 ((int)$o) != 180 && ((int)$o) != 270)) {
			throw new Exception("InvalidOrientationException: ".$o);
		}
		$this->orientation = $o;
	}
	
	public function value() {
		return $this->orientation;
	}
}

class Media {
    
    private $id;
    private $trip_id;
	private $time_captured;
	private $time_published;
    private $latitude;
    private $longitude;
    private $altitude;
	private $audio_filename;
	private $photo_filename;
	private $photo_orientation;
    
    public function __construct($arr) {
    	if (isset($arr['id'])) {
    		$this->id = new ID($arr['id']);
    	}
	    if (isset($arr['trip_id'])) {
	    	$this->trip_id = new ID($arr['trip_id']);
	    }
		if (isset($arr['time_captured'])) {
			$this->time_captured = new Timestamp($arr['time_captured']);
		}
		if (isset($arr['time_published'])) {
			$this->time_published = new Timestamp($arr['time_published']);
		}
	    if (isset($arr['latitude'])) {
	    	$this->latitude = new Latitude($arr['latitude']);
	    }
	    if (isset($arr['longitude'])) {
	    	$this->longitude = new Longitude($arr['longitude']);
   		}
	    if (isset($arr['altitude'])) {
	    	$this->altitude = new Altitude($arr['altitude']);
	    }
	    if (isset($arr['audio_filename'])) {
	    	$this->audio_filename = new URL($arr['audio_filename']);
	    }
	    if (isset($arr['photo_filename'])) {
	    	$this->photo_filename = new URL($arr['photo_filename']);
	    }
	    if (isset($arr['photo_orientation'])) {
	    	$this->photo_orientation = new Orientation($arr['photo_orientation']);
	    }
    }
    
    public function __destruct() {
        // no-op
    }

	/* ACCESSOR & MUTATOR FUNCTIONS */
	public function id() {
		if ($this->id != null) {
			return $this->id->value();
		}
		return null;
	}
	
	public function trip_id() {
		if ($this->trip_id != null) {
			return $this->trip_id->value();
		}
		return null;
	}
	
	/**
	 * NOTE: return Timestamp so that the
	 * month(), day(), and year() functions
	 * are available.
	 */
	public function time_captured() {
		if ($this->time_captured != null) {
			return $this->time_captured;
		}
		return null;
	}
	
	/**
	 * NOTE: return Timestamp so that the
	 * month(), day(), and year() functions
	 * are available.
	 */
	public function time_published() {
		if ($this->time_published != null) {
			return $this->time_published;
		}
		return null;
	}
	
	public function latitude() {
		if ($this->latitude != null) {
			return $this->latitude->value();
		}
		return null;
	}
	
	public function longitude() {
		if ($this->longitude != null) {
			return $this->longitude->value();
		}
		return null;
	}
	
	public function altitude() {
		if ($this->altitude != null) {
			return $this->altitude->value();
		}
		return null;
	}

	public function audio_filename() {
		if ($this->audio_filename != null) {
			return $this->audio_filename->value();
		}
		return null;
	}
	
	public function audio_filename_is($u) {
		$this->audio_filename = new URL($u);
	}
	
	public function photo_filename() {
		if ($this->photo_filename != null) {
			return $this->photo_filename->value();
		}
		return null;
	}
	
	public function photo_filename_is($u) {
		$this->photo_filename = new URL($u);
	}
	
	public function photo_orientation() {
		return $this->photo_orientation->value();
	}
	
	public function thumbnail_filename() {
		if ($this->photo_filename != null) {
			
		}
		return null;
	}
    
    /**
     * Inserts this media object into the database.
     * Resolves the parent_id to point to the parent object
     * NOTE: this function is only to be used after import from phone!
     */
    public function save() {
		$db_conn = new DBConn();
		
		$column_names = array();
		$column_values = array();

		foreach (get_object_vars($this) as $key => $value) {
			if ($key === "id") continue; // let id auto-increment
			if ($value == null || $value->value() == null) continue;
			
			$column_names[] = $key;
			$column_values[] = $db_conn->sanitize($value->value());
		}
		
		$sql = "INSERT INTO media (" . implode(',', $column_names) . ") VALUES (" . implode(',', $column_values) . ");";
		
		if (!$db_conn->query($sql)) {
			throw new Exception("SaveException");
		}
    }
    
    /**
     * Serializes the contents of this media object into XML
     * format for output to the Flash widget.
     */
    public function serialize() {
    	$xml_string = "<".$this->media_type();
    	
    	foreach (get_object_vars($this) as $key => $value) {
    		$value_str = "";
    		if ($value == null || $value->value() == null) {
    			$value_str = "NULL";
    		} else {
				$value_str = htmlspecialchars($value->value(), ENT_QUOTES, "UTF-8", true);
    		}
    		
    		$xml_string .= " $key=\"$value_str\"";
    	}
    	
    	$xml_string .= " />";
    	return $xml_string;
    }
    
}

?>
